(function() {
  var Config, Crypto, Gzippo, Logger, Path, RedisClient, TTL, Zlib, cacheHandler, cacheKeyPrefix, clientMaxAge, getHashKey, gzipOptions, gzippoHandler, isHTTPWebRequest, isUserInfoRequest, renderAndCache, responseUserInfoRequest, setHTMLCache, staticHandler, staticPrefix;

  Config = require('../config');

  Gzippo = require('gzippo');

  Path = require('path');

  Zlib = require('zlib');

  Crypto = require('crypto');

  Logger = require('log4js').getLogger();

  if (!Config.debug) {
    RedisClient = require('../models/redis_client');
  }

  staticPrefix = Config.server.staticPrefix;

  clientMaxAge = 60 * 60 * 1000;

  if (Config.debug) {
    clientMaxAge = 1000;
  }

  gzipOptions = {
    prefix: staticPrefix,
    clientMaxAge: clientMaxAge
  };

  gzippoHandler = Gzippo.staticGzip(Path.join(__dirname, '../', 'statics'), gzipOptions);

  TTL = 10 * 60;

  cacheKeyPrefix = 'vicanso_html_';

  /**
   * [staticHandler description]
   * @param  {[type]}   req  [description]
   * @param  {[type]}   res  [description]
   * @param  {Function} next [description]
   * @return {[type]}        [description]
  */


  staticHandler = function(req, res, next) {
    return gzippoHandler(req, res, next);
  };

  /**
   * [cacheHandler description]
   * @param  {[type]}   req  [description]
   * @param  {[type]}   res  [description]
   * @param  {Function} next [description]
   * @return {[type]}        [description]
  */


  cacheHandler = function(req, res, next) {
    var key;
    if (isUserInfoRequest(req)) {
      responseUserInfoRequest(req, res);
      return;
    }
    if (!isHTTPWebRequest(req) || !RedisClient) {
      next();
      return;
    }
    key = getHashKey(req);
    return RedisClient.hgetall(key, function(err, data) {
      var acceptEncoding, gzipData;
      if (err || !data) {
        return next();
      } else {
        acceptEncoding = req.header('accept-encoding');
        if (data.gzip && (acceptEncoding != null ? acceptEncoding.indexOf('gzip') : void 0) !== -1) {
          res.header('Content-Encoding', 'gzip');
          res.header('Content-Type', 'text/html');
          res.header('Cache-Control', "public, max-age=" + TTL);
          gzipData = new Buffer(data.gzip, 'binary');
          return res.send(gzipData);
        } else if (data.html) {
          res.header('Content-Type', 'text/html');
          res.header('Cache-Control', "public, max-age=" + TTL);
          return res.send(data.html);
        } else {
          return next();
        }
      }
    });
  };

  /**
   * [renderAndCache description]
   * @param  {[type]} req  [description]
   * @param  {[type]} res  [description]
   * @param  {[type]} view [description]
   * @param  {[type]} data [description]
   * @param  {[type]} ttl  [description]
   * @return {[type]}      [description]
  */


  renderAndCache = function(req, res, view, data, ttl) {
    var key;
    if (arguments.length < 4) {
      Logger.error('renderAndCache function, the arguments is less than 4');
      res.send('renderAndCache function, the arguments is less than 4', 504);
      return;
    }
    key = getHashKey(req);
    return res.render(view, data, function(err, html) {
      if (err) {
        Logger.error(err);
        res.send(err, 500);
      } else {
        if (ttl == null) {
          ttl = TTL;
        }
        setHTMLCache(key, html, ttl);
      }
      res.header('Content-Type', 'text/html');
      res.header('Cache-Control', "public, max-age=" + TTL);
      return res.send(html);
    });
  };

  isUserInfoRequest = function(req) {
    if (req.url.indexOf('/static/ys/user_info.js') === 0) {
      return true;
    }
    return false;
  };

  responseUserInfoRequest = function(req, res) {
    var host, userInfo, _ref;
    res.header('Content-Type', 'application/javascript; charset=UTF-8');
    res.header('Cache-Control', 'no-cache, no-store, max-age=0');
    host = 'http://' + ((_ref = req.headers) != null ? _ref.host : void 0);
    userInfo = {
      host: host,
      paths: {
        home: '/ys',
        table: '/ys/table'
      }
    };
    return res.send('var USER_INFO = ' + JSON.stringify(userInfo));
  };

  /**
   * [isHTTPWebRequest description]
   * @param  {[type]}  req [description]
   * @return {Boolean}     [description]
  */


  isHTTPWebRequest = function(req) {
    if (req.xhr || !req.accepts('html')) {
      return false;
    }
    return true;
  };

  /**
   * [getHashKey description]
   * @param  {[type]} req [description]
   * @return {[type]}     [description]
  */


  getHashKey = function(req) {
    var key;
    key = req.cacheKey;
    if (!key) {
      key = cacheKeyPrefix + Crypto.createHash('md5').update(req.url).digest('base64');
      req.cacheKey = key;
    }
    return key;
  };

  /**
   * [setHTMLCache description]
   * @param {[type]} key  [description]
   * @param {[type]} html [description]
   * @param {[type]} ttl  [description]
  */


  setHTMLCache = function(key, html, ttl) {
    if (RedisClient != null) {
      return RedisClient.hmset(key, 'html', html, function(err) {
        if (!err) {
          RedisClient.expire(key, ttl);
          return Zlib.gzip(html, function(err, data) {
            if (!err) {
              return RedisClient.hmset(key, 'gzip', data.toString('binary'));
            }
          });
        }
      });
    }
  };

  module.exports = {
    staticHandler: staticHandler,
    cacheHandler: cacheHandler,
    renderAndCache: renderAndCache
  };

}).call(this);
